import os
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import cv2
import matlab.engine
import scipy.io as scio
import math
import itertools

eng = matlab.engine.start_matlab()
#
#
# def plt_make(data, x_label, y_label, title):
#     '''
#     :param data: 生成直方图的数据
#     :param x_label: x轴的标签
#     :param y_label: y轴的标签
#     :param title: 图片标题
#     :return:
#     '''
#     # plt.rcParams['font.sans - serif'] = ['SimHei']
#     print(data.shape)
#     comment = pd.Series(data)
#     print(comment.value_counts())
#     comment.plot.hist(grid=True, bins=np.arange(-20, 20, 1),
#                       color='#607c8e')
#     plt.title(title)
#     plt.xlim((-20, 20))
#     plt.xlabel(x_label)
#     plt.ylabel(y_label)
#     plt.grid(axis='y', alpha=0.75)
#     # plt.legend(prop={'size': 10})
#     plt.show()


def Over_flow(img, flag):
    '''
    防止溢出
    :param img:
    :return:
    '''
    row, col = img.shape
    lcm = np.zeros(col * row)
    index = 0
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            if np.mod(i + j, 2) == 0 and flag == 0:
                index += 1
                if img[i][j] == 0:
                    img[i][j] == 1
                    lcm[index] = 1
                if img[i][j] == 255:
                    img[i][j] = 254
                    lcm[index] = 1
            if np.mod(i + j, 2) == 1 and flag == 1:
                index += 1
                if img[i][j] == 0:
                    img[i][j] == 1
                    lcm[index] = 1
                if img[i][j] == 255:
                    img[i][j] = 254
                    lcm[index] = 1
    xc = np.empty((1, 1), dtype=object)
    for i in range(1):
        for k in range(1):
            xc[i, k] = np.zeros((1, col * row))
    print('xc', xc.shape)
    # # xC = {}
    xc[0][0] = lcm
    print(xc)
    file_name = 'data.mat'
    scio.savemat(file_name, {'xc': lcm})
    # data = eng.test()
    data = eng.test()
    return img, lcm, index, data


def searchbins(H, ECR):
    bins = np.zeros(16);
    # R = C / D;
    # EC = 0;
    # L = len(W);
    Dmin = 10000000000000000
    # u7 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 250]
    u7 = [0, 1, 2, 3, 4, 5, 6, 7, 250]
    L = len(u7)
    for a1 in range(0, L):
        for a2 in range(a1, L):
            for a3 in range(a2, L):
                for a4 in range(a3, L):
                    for a5 in range(a4, L):
                        for a6 in range(a5, L):
                            for a7 in range(a6, L):
                                for a8 in range(a7, L):
                                    for a9 in range(a8, L):
                                        for a10 in range(a9, L):
                                            for a11 in range(a10, L):
                                                for a12 in range(a11, L):
                                                    for a13 in range(a12, L):
                                                        for a14 in range(a13, L):
                                                            for a15 in range(a14, L):
                                                                for a16 in range(a15, L):
                                                                    S = [u7[a1], u7[a2], u7[a3], u7[a4], u7[a5],
                                                                         u7[a6], u7[a7], u7[a8], u7[a9], u7[a10],
                                                                         u7[a11], u7[a12], u7[a13], u7[a14],
                                                                         u7[a15], u7[a16]]
                                                                    x = 0
                                                                    for k in range(16):
                                                                        x = x + H[S[k] + 254, k] + H[-S[k] - 1 + 254, k]
                                                                    if x >= ECR:
                                                                        y = 0
                                                                        for k in range(16):
                                                                            y = y + np.sum(
                                                                                H[S[k] + 254:512,
                                                                                k]) + np.sum(
                                                                                H[0:-S[k] - 1 + 255, k])
                                                                        if y / x < Dmin:
                                                                            Dmin = y / x
                                                                            bins = S
    print('this is bins', bins)
    # print('this is test', test)
    return bins


class Load_img():
    '''
        初始化加载图像，通过getitem方法可以直接将所有的图片通过cv2将图片加载
    '''

    def __init__(self, root_dir):
        '''
        :param root_dir: 选择图形所在目录
        '''
        self.root_dir = root_dir
        self.path = os.path.join(self.root_dir)
        self.img_path = os.listdir(self.path)
    def __getitem__(self, item):
        img_name = self.img_path[item]
        img_item_path = os.path.join(self.root_dir, img_name)
        print(img_item_path)
        # 直接获取灰度图
        img = cv2.imread(img_item_path, 0)
        return img


def img_division(img, flag):
    '''
        读取图形的数据，计算图像的复杂度给图像分类
        :param img:图像
        :param flag:判断是奇数点还是偶数点
        return 返回lc为复杂度矩阵，erromap为误差矩阵，predict为预测像素矩阵

    '''
    row, col = img.shape
    # 复杂度
    Complexity = np.zeros((row, col))
    # 预测点
    predict = np.zeros((row, row))
    # 误差值
    erromap = np.zeros((row, row))
    # row,col获取图像的行和列lc先定义一个和图像尺寸相同的0矩阵data ，label 为空列表
    index = 0
    for r in range(1, row - 2):
        for c in range(1, col - 2):
            if np.mod(r + c, 2) == 0 and flag == 0:
                v1 = int(img[r - 1][c])
                v2 = int(img[r][c - 1])
                v3 = int(img[r + 1][c])
                v4 = int(img[r][c + 1])  # 像素上下左右四个像素
                x = int(img[r][c])
                u6 = int(img[r - 1][c + 2])
                u7 = int(img[r][c + 2])
                u1 = int(img[r + 1][c - 1])
                u4 = int(img[r + 1][c + 1])
                u8 = int(img[r + 1][c + 2])
                u2 = int(img[r + 2][c - 1])
                u3 = int(img[r + 2][c])
                u5 = int(img[r + 2][c + 1])
                u9 = int(img[r + 2][c + 2])
                # u6到u9为像素周围的九个圈的像素
                f0 = abs(v2 - u1)
                f1 = abs(u1 - u2)
                f2 = abs(v3 - u3)
                f3 = abs(v4 - u4)
                f4 = abs(u4 - u5)
                f5 = abs(u6 - u7)
                f6 = abs(u7 - u8)
                f7 = abs(u8 - u9)
                f8 = abs(v4 - u7)
                fL = abs(u1 - v3)
                f_0 = abs(v3 - u4)
                f_1 = abs(u4 - u8)
                f_2 = abs(u2 - u3)
                f_3 = abs(u3 - u5)
                f_4 = abs(u5 - u9)

                four_neighbor = np.array(
                    [int(v1), int(v2), int(v3), int(v4)])
                p = int(np.ceil(np.average(four_neighbor)))
                D = abs(v2 - u1) + abs(u1 - u2) + abs(v1 - p) + abs(p - v3) + abs(v3 - u3) + abs(v4 - u4) + abs(
                    u4 - u5) + abs(u6 - u7) + abs(u7 - u8) + abs(u8 - u9) + abs(v2 - p) + abs(p - v4) + abs(
                    v4 - u7) + abs(u1 - v3) + abs(v3 - u4) + abs(u4 - u8) + abs(u2 - u3) + abs(u3 - u5) + abs(
                    u5 - u9)
                Complexity[r][c] = D

                predict[r][c] = int(p)
                erromap[r][c] = int(img[r][c]) - int(p)
                if erromap[r][c] == 0:
                    index += 1
            if np.mod(r + c, 2) == 1 and flag == 1:
                v1 = int(img[r - 1][c])
                v2 = int(img[r][c - 1])
                v3 = int(img[r + 1][c])
                v4 = int(img[r][c + 1])  # 像素上下左右四个像素
                x = int(img[r][c])
                u6 = int(img[r - 1][c + 2])
                u7 = int(img[r][c + 2])
                u1 = int(img[r + 1][c - 1])
                u4 = int(img[r + 1][c + 1])
                u8 = int(img[r + 1][c + 2])
                u2 = int(img[r + 2][c - 1])
                u3 = int(img[r + 2][c])
                u5 = int(img[r + 2][c + 1])
                u9 = int(img[r + 2][c + 2])
                # u6到u9为像素周围的九个圈的像素
                f0 = abs(v2 - u1)
                f1 = abs(u1 - u2)
                f2 = abs(v3 - u3)
                f3 = abs(v4 - u4)
                f4 = abs(u4 - u5)
                f5 = abs(u6 - u7)
                f6 = abs(u7 - u8)
                f7 = abs(u8 - u9)
                f8 = abs(v4 - u7)
                fL = abs(u1 - v3)
                f_0 = abs(v3 - u4)
                f_1 = abs(u4 - u8)
                f_2 = abs(u2 - u3)
                f_3 = abs(u3 - u5)
                f_4 = abs(u5 - u9)
                four_neighbor = np.array(
                    [int(v1), int(v2), int(v3), int(v4)])
                p = int(np.ceil(np.average(four_neighbor)))
                D = abs(v2 - u1) + abs(u1 - u2) + abs(v1 - p) + abs(p - v3) + abs(v3 - u3) + abs(v4 - u4) + abs(
                    u4 - u5) + abs(u6 - u7) + abs(u7 - u8) + abs(u8 - u9) + abs(v2 - p) + abs(p - v4) + abs(
                    v4 - u7) + abs(u1 - v3) + abs(v3 - u4) + abs(u4 - u8) + abs(u2 - u3) + abs(u3 - u5) + abs(
                    u5 - u9)
                Complexity[r][c] = D
                predict[r][c] = int(p)
                erromap[r][c] = int(img[r][c]) - int(p)
                if erromap[r][c] == 0:
                    index += 1
    print('em_index', index)
    return Complexity, erromap, predict


def divide_hs(Complexity, erromap, flag):
    '''
        2d直方图
    '''
    row, col = Complexity.shape
    # 直方图序列
    print('compu', np.max(Complexity))
    hs = np.zeros((512, int(np.max(Complexity) + 1)))
    print(hs.shape)
    for i in range(1, row - 2):
        for j in range(1, col - 2):
            if np.mod(i + j, 2) == 0 and flag == 0:
                hs[int(erromap[i][j] + 255)][int(Complexity[i][j])] += 1
            if np.mod(i + j, 2) == 1 and flag == 1:
                hs[int(erromap[i][j] + 255)][int(Complexity[i][j])] += 1
    return hs



# ----------------------------------------李小龙版本start
def guiyi(k, Complexity, hs, size):
    '''
        k:划分的区间
        complexity:复杂度矩阵
        hs:2d直方图,
        进行区间划分，划分16个区间，每个区间保证对应有相等数量的坐标点
    '''
    T = np.zeros(k)
    for i in range(k):
        for j in range(int(np.max(Complexity)) + 2):
            # print(np.sum(np.sum(hs[:, 1:j])))
            if np.sum(np.sum(hs[:, 0:j])) >= ((size / k) * (i + 1)):
                T[i] = j
                break
    return T


def recomplex(row, col, k, T, flag, complex):
    '''
        row,col长宽
        k分割线区间
        T归一化后断点
        flag 奇偶
        complex原先的复杂度
    '''
    # 新的复杂度矩阵
    Dbis = np.zeros((row, col))
    for i in range(k - 1, -1, -1):
        for j in range(1, row - 2):
            for m in range(1, col - 2):
                if np.mod(m + j, 2) == 0 and flag == 0:
                    if complex[j][m] < T[i]:
                        Dbis[j][m] = i + 1
                if np.mod(m + j, 2) == 1 and flag == 1:
                    if complex[j][m] < T[i]:
                        Dbis[j][m] = i + 1
    return Dbis


# def re_hs(k, row, col, Dbis, flag, em):
#     Hs = np.zeros((511, k))
#     for i in range(1, row - 2):
#         for j in range(1, col - 2):
#             if np.mod(i + j, 2) == 0 and flag == 0:
#                 Hs[int(em[i][j] + 254)][int(Dbis[i][j]) - 1] += 1
#             if np.mod(i + j, 2) == 1 and flag == 1:
#                 Hs[int(em[i][j] + 254)][int(Dbis[i][j]) - 1] += 1
#     return Hs


def cal_aux1(s, k, lcm, T, data_length):
    '''
        k 是分割数量
        lcm是localtionmapc
        t是分割区间
    '''
    print('s,k', [s, k])
    if np.sum(lcm) == 0:
        Aux = k * 3 + 4 + 1 + 17 + (k - 1) * s + 4
    else:
        Aux = k * 3 + 4 + 1 + 8 * data_length + 17 + 17 + (k - 1) * s + 4
    return Aux


def cal_aux2(s, SIB, lcm, T, data_length):
    '''
        k 是分割数量
        lcm是localtionmapc
        t是分割区间
    '''
    print('s2,scale', [s, SIB])
    if np.sum(lcm) == 0:
        Aux = SIB * 3 + 4 + 1 + 17 + SIB * s + 4
    else:
        Aux = SIB * 3 + 4 + 1 + 8 * data_length + 17 + 17 + SIB * s + 4
    return Aux


# -------------------------------李小龙版本end

def cal_psnr(img, img_hide, ec):
    A, B = img.shape
    mse = 0
    PSNR = 0
    mse = int(np.sum(np.sum(np.square(img - img_hide))))
    print('mse',mse)
    if np.sum(ec) == 0:
        PSNR = 10 * np.log10((A * B * 255 * 255) / mse)
    return PSNR




def secret_msg(row, col):
    '''
    :param ec: 需要嵌入的容量
    :return: 生成随机生成的二进制
    '''
    arr = np.arange(row * col)
    np.random.shuffle(arr)
    secret_msg = np.zeros((row, col))
    for i in range(row):
        for j in range(col):
            # secret_msg[i, j] = np.mod(arr[col*(i+1)-j-1],2)
            secret_msg[i, j] = np.mod(arr[col * (i + 1) - j - 1], 2)
    return secret_msg




def Lsb_insert(row, col, anx, img_hide2, flags, anx_secret):
    for i in range(1, row - 2):
        for j in range(1, col - 2):
            if np.mod(i + j, 2) == 0 and flags == 0:
                if anx > 0:
                    img_hide2[i][j] = 2 * np.floor(img_hide2[i][j] / 2) + anx_secret[i][j]
                    anx = anx - 1
            if np.mod(i + j, 2) == 1 and flags == 1:
                if anx > 0:
                    img_hide2[i][j] = 2 * np.floor(img_hide2[i][j] / 2) + anx_secret[i][j]
                    anx = anx - 1
    return img_hide2
